
#include "io_poll.h"

#include "io_epoll.h"
#include "io_reuse_module.h"

#include <cstdint>
#include <cstdio>
#include <sys/epoll.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <vector>

std::shared_ptr<IoReuseModuleImpl> IoPollFactory::CreateModule()
{
    auto ptr = std::make_shared<IoEpoll>();
    return ptr;
}

IoPoll::IoPoll(int size)
{
    m_index = 1;
    m_poll_vec.resize(size);
}

IoPoll::~IoPoll()
{

}

int IoPoll::AddPollEvent(struct pollfd & event)
{
    int64_t index = m_index++;
    m_poll_map[index] = event;
    m_fd_index_map[event.fd] = index;

    return 0;
}

int IoPoll::ModPollEvent(struct pollfd & event)
{
    auto index_iter = m_fd_index_map.find(event.fd);
    if (index_iter != m_fd_index_map.end())
    {
        m_poll_map[index_iter->second] = event;
    }
    return 0;
}

int IoPoll::DelPollEvent(struct pollfd & event)
{
    auto index_iter = m_fd_index_map.find(event.fd);
    if (index_iter != m_fd_index_map.end())
    { 
        m_poll_map.erase(index_iter->second);
        m_fd_index_map.erase(index_iter);
    }
    return 0;
}

int IoPoll::PollWait(std::vector<struct pollfd> & poll_vec, int wait_time)
{
    std::vector<struct pollfd> poll_vec_trigger;
    for (auto & data : m_poll_map)
    {
        data.second.revents = 0;
        poll_vec_trigger.push_back(data.second);
    }
    int result_size = poll(&(*poll_vec_trigger.begin()), poll_vec_trigger.size(), wait_time);
    /* printf("poll function result : %d.\n", result_size); */
    if (result_size > 0)
    {
        for (auto & data : poll_vec_trigger)
        {
            if (data.revents != -0)
            {
                poll_vec.push_back(data);
            }
            if ((int)poll_vec.size() == result_size)
            {
                break;
            }
        }
    }
    return result_size;
}

int IoPoll::WaitEvent(std::vector<struct EventData> & trigger_data, int wait_time)
{
    std::vector<struct pollfd> poll_vec_trigger;
    for (auto & data : m_poll_map)
    {
        data.second.revents = 0;
        poll_vec_trigger.push_back(data.second);
    }
    int result_size = poll(&(*poll_vec_trigger.begin()), poll_vec_trigger.size(), wait_time);
    if (result_size > 0)
    {
        for (auto & data : poll_vec_trigger)
        {
            if (data.revents != 0)
            {
                EventData event;
                event.id = m_fd_index_map[data.fd];
                event.events = ((data.revents & POLLIN ? EmIoIn : 0)  | (data.revents & POLLOUT ? EmIoOut : 0) | (data.revents & POLLERR ? EmIoErr : 0) | (data.revents & POLLRDHUP ? EmIoRdHup : 0)); 
                trigger_data.push_back(event);
            }
            if ((int)trigger_data.size() == result_size)
            {
                break;
            }
        }
    }
    return result_size;
}

int64_t IoPoll::AddEvent(int description, int event)
{
    int64_t index = m_index++;
    struct pollfd poll_event;
    poll_event.events = 0;
    poll_event.fd     = description;
    if (event & EmIoIn)
    {
        poll_event.events |= POLLIN;
    }
    if (event & EmIoOut)
    { 
        poll_event.events |= POLLOUT;
    }
    if (event & EmIoErr)
    { 
        poll_event.events |= POLLERR;
    }
    if (event & EmIoRdHup)
    {
        poll_event.events |= POLLRDHUP;
    }
    m_fd_index_map[description] = index;
    m_poll_map[index] = poll_event;
    return index;
}

int64_t IoPoll::ModEvent(int64_t id, int event)
{
    auto iter = m_poll_map.find(id);
    if (iter != m_poll_map.end())
    {
        struct pollfd & poll_event = iter->second;
        poll_event.events = 0;
        if (event & EmIoIn)
        {
            poll_event.events |= POLLIN;
        }
        if (event & EmIoOut)
        { 
            poll_event.events |= POLLOUT;
        }
        if (event & EmIoErr)
        { 
            poll_event.events |= POLLERR;
        }
        if (event & EmIoRdHup)
        {
            poll_event.events |= POLLRDHUP;
        }
        return 0;
    }
    return -1;
}

int64_t IoPoll::DelEvent(int64_t id)
{
    auto iter = m_poll_map.find(id);
    if (iter != m_poll_map.end())
    {
        m_fd_index_map.erase(iter->second.fd);
        m_poll_map.erase(iter);
    }
    return 0;
}



